﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp1.Test
{
    public class Class6
    {
        void Test60()
        {
            Test60_1();

            Thread.Sleep(3000);

            var tcpServerIp = "127.0.0.1";
            var tcpServerPort = "8080";

            var tcpClientInit = Test60_2(tcpServerIp, tcpServerPort);

            var tcpClientDic = new ConcurrentDictionary<string, TouchSocket.Sockets.TcpClient>();
            tcpClientDic.TryAdd($"{tcpServerIp}:{tcpServerPort}", tcpClientInit);

            while (true)
            {
                try
                {
                    foreach (var item in tcpClientDic)
                    {
                        var tcpClient = item.Value;

                        var isOnline = tcpClient?.Online ?? false;

                        if (tcpClient?.DisposedValue ?? true)
                        {
                            isOnline = false;

                            var tcpServerIpPort = item.Key.Split(":");
                            var _tcpServerIp = tcpServerIpPort[0];
                            var _tcpServerPort = tcpServerIpPort[1];

                            tcpClientDic[item.Key] = tcpClient = Test60_2(_tcpServerIp, _tcpServerPort);
                        }

                        if (!isOnline)
                        {
                            XTrace.WriteLine("TryConnect");

                            Result result = tcpClient.TryConnect();

                            XTrace.WriteLine(result.ToJsonString());
                        }
                        else
                        {
                            XTrace.WriteLine("IsOnline");
                        }

                        if (isOnline)
                        {
                            try
                            {
                                XTrace.WriteLine("Send Data:1");
                                //tcpClient.Send("101");
                                tcpClient.Send("**10102##");
                                tcpClient.Send("@@10103$$");
                            }
                            catch (Exception exp)
                            {
                                tcpClient.Close();

                                XTrace.WriteException(exp);
                            }
                        }
                    }
                }
                catch (Exception exp)
                {
                    XTrace.WriteException(exp);
                }
                finally
                {
                    Thread.Sleep(5000);
                }
            }
        }

        async Task Test60_1()
        {
            var service = new TcpService();
            service.Connecting = (client, e) =>
            {
                XTrace.WriteLine($"[Server:{client.ServiceIP}:{client.ServicePort}] <<< [Client:{client?.IP}:{client?.Port}] Connecting");
                return EasyTask.CompletedTask;
            };
            service.Connected = (client, e) =>
            {
                XTrace.WriteLine($"[Server:{client.ServiceIP}:{client.ServicePort}] <<< [Client:{client?.IP}:{client?.Port}] Connected");
                return EasyTask.CompletedTask;
            };
            service.Closing = (client, e) =>
            {
                XTrace.WriteLine($"[Server:{client.ServiceIP}:{client.ServicePort}] <<< [Client:{client?.IP}:{client?.Port}] Closing");
                return EasyTask.CompletedTask;
            };
            service.Closed = (client, e) =>
            {
                XTrace.WriteLine($"[Server:{client.ServiceIP}:{client.ServicePort}] <<< [Client:{client?.IP}:{client?.Port}] Closed");
                return EasyTask.CompletedTask;
            };
            service.Received = async (client, e) =>
            {
                var mes = string.Empty;

                if (e.RequestInfo is BetweenAndRequestInfo1 request1)
                {
                    mes = Encoding.UTF8.GetString(request1.Body);

                    XTrace.WriteLine($"[Server:{client.ServiceIP}:{client.ServicePort}] <<< [Client:{client?.IP}:{client?.Port}] [Received request1:{mes}]");
                }
                else if (e.RequestInfo is BetweenAndRequestInfo2 request2)
                {
                    mes = Encoding.UTF8.GetString(request2.Body);

                    XTrace.WriteLine($"[Server:{client.ServiceIP}:{client.ServicePort}] <<< [Client:{client?.IP}:{client?.Port}] [Received request2:{mes}]");
                }
                else
                {
                    //从客户端收到信息
                    mes = e.ByteBlock.Span.ToString(Encoding.UTF8);
                }

                XTrace.WriteLine($"[Server:{client.ServiceIP}:{client.ServicePort}] <<< [Client:{client?.IP}:{client?.Port}] [Received:{mes}]");
            };

            await service.SetupAsync(new TouchSocketConfig()//载入配置
                 .SetListenIPHosts(8080, 8081)//可以同时监听两个地址
                 .ConfigureContainer(a =>//容器的配置顺序应该在最前面
                 {
                     //a.AddConsoleLogger();//添加一个控制台日志注入（注意：在maui中控制台日志不可用）
                 })
                  .SetTcpDataHandlingAdapter(() => new BetweenAndDataHandlingAdapter1())
                  .SetTcpDataHandlingAdapter(() => new BetweenAndDataHandlingAdapter2())
                 .ConfigurePlugins(a =>
                 {
                     a.UseCheckClear()
                     .SetCheckClearType(CheckClearType.All)
                     .SetTick(TimeSpan.FromSeconds(10))
                     .SetOnClose((c, t) =>
                     {
                         var serverEndPoint = string.Empty;
                         if (c is TcpSessionClient client)
                         {
                             serverEndPoint = $"{client.ServiceIP}:{client.ServicePort}";
                         }

                         XTrace.WriteLine($"[Server:{serverEndPoint}] >>> [Client:{c?.IP}:{c?.Port}] [TryShutdown:{c.TryShutdown()}]");

                         c.SafeClose("LONG TIME NO DATA");
                     });
                 })
                  .ConfigurePlugins(A =>
                  {
                      A.Add<HeartbeatAndReceivePlugin>();
                  }));
            await service.StartAsync();//启动
        }

        TouchSocket.Sockets.TcpClient Test60_2(string tcpServerIp, string tcpServerPort)
        {
            var tcpClient = new TouchSocket.Sockets.TcpClient();
            tcpClient.Connecting = (client, e) =>
            {
                XTrace.WriteLine($"[Client] >>> [Server:{tcpClient?.RemoteIPHost}] Connecting");

                return EasyTask.CompletedTask;
            };

            tcpClient.Connected = (client, e) =>
            {
                XTrace.WriteLine($"[Client:{client?.MainSocket?.LocalEndPoint}] >>> [Server:{tcpClient?.RemoteIPHost}] Connected");

                return EasyTask.CompletedTask;
            };
            tcpClient.Closing = (client, e) =>
            {
                XTrace.WriteLine($"[Client:{client?.MainSocket?.LocalEndPoint}] >>> [Server:{tcpClient?.RemoteIPHost}] Closing");

                return EasyTask.CompletedTask;
            };
            tcpClient.Closed = (client, e) =>
            {
                XTrace.WriteLine($"[Client] >>> [Server:{tcpClient?.RemoteIPHost}] Closed");

                return EasyTask.CompletedTask;
            };
            tcpClient.Received = (client, e) =>
            {
                var mes = e.ByteBlock.Span.ToString(Encoding.UTF8);

                XTrace.WriteLine($"[Client:{client?.MainSocket?.LocalEndPoint}] <<< [Server:{tcpClient?.RemoteIPHost}] [Received:{mes}]");

                return EasyTask.CompletedTask;
            };

            //载入配置
            tcpClient.Setup(new TouchSocketConfig()
                 .SetRemoteIPHost($"{tcpServerIp}:{tcpServerPort}")
                 .ConfigureContainer(a =>
                 {
                     //a.AddConsoleLogger();//添加一个日志注入
                 })
                 
                 .ConfigurePlugins(A =>
                 {
                     A.UseTcpReconnection()
                     .UsePolling(TimeSpan.FromSeconds(10))

                     .SetActionForCheck(async (c, i) =>//重新定义检活策略
                      {
                          //方法2，直接ping，如果true，则客户端必在线。如果false，则客户端不一定不在线，原因是可能当前传输正在忙
                          if (await tcpClient.PingAsync())
                          {
                              return true;
                          }
                          //返回false时可以判断，如果最近活动时间不超过3秒，则猜测客户端确实在忙，所以跳过本次重连
                          else if (DateTime.Now - c.GetLastActiveTime() < TimeSpan.FromSeconds(3))
                          {
                              return null;
                          }
                          //否则，直接重连。
                          else
                          {
                              return false;
                          }
                      });

                 }));

            return tcpClient;
        }

        void Test59()
        {
            var dic = new ConcurrentDictionary<string, Student>() { };
            dic.TryAdd("A", new Student() { Id = 1, Name = "A", Age = 31 });
            dic.TryAdd("B", new Student() { Id = 2, Name = "B", Age = 32 });
            dic.TryAdd("C", new Student() { Id = 3, Name = "C", Age = 33 });

            foreach (var item in dic)
            {
                if (item.Key == "B")
                {
                    var item1 = item.Value;
                    item1 = new Student() { Id = 22, Name = "BB", Age = 23 };
                }
            }

            XTrace.WriteLine(dic["B"].ToJsonString());


        }
        void Test58()
        {
            XTrace.WriteLine("abcd,123".StartsWith("abc").ToString());
        }

        void Test57()
        {
            XTrace.WriteLine(Environment.GetEnvironmentVariable("LANG"));
        }

        void Test56()
        {
            // 实例化Redis，默认端口6379可以省略，密码有两种写法
            var _redis = new FullRedis("127.0.0.1:6379", null, 1);
            _redis.Log = XTrace.Log;
            _redis.ClientLog = XTrace.Log; // 调试日志。正式使用时注释


            var key = "ReliableQueue";

            // 删除已有
            //_redis.Remove(key);
            var queue = _redis.GetReliableQueue<String>(key);
            queue.RetryInterval = 5;

            // 发现回滚
            //var rcount = queue.RollbackAllAck();
            //if (rcount > 0)
            //{
            //    XTrace.WriteLine($"回滚：{rcount}");

            //    var rcount2 = _redis.Remove(key);
            //}

            // 取出个数
            var count = queue.Count;

            XTrace.WriteLine($"IsEmpty:{queue.IsEmpty}");
            XTrace.WriteLine($"IsEmpty count:{count}");

            // 添加
            var vs = new[] { "1", "3", "2", "4" };
            foreach (var item in vs)
            {
                queue.Add(item);
            }

            // 取出来
            var vs2 = new[] { queue.TakeOne(), queue.TakeOne(), queue.TakeOne(), };

            XTrace.WriteLine($"vs2[0]:{vs2[0]}");
            XTrace.WriteLine($"vs2[1]:{vs2[1]}");
            XTrace.WriteLine($"vs2[2]:{vs2[2]}");
            XTrace.WriteLine($"queue.Count:{queue.Count}");


            // 检查Ack队列
            var ackList = _redis.GetList<String>(queue.AckKey);


            // 确认两个，留下一个未确认消息在Ack队列
            var rs = queue.Acknowledge(vs2[0]) + queue.Acknowledge(vs2[1]);

            // 捞出来Ack最后一个
            var vs3 = queue.TakeAck(3).ToArray();

            // 读取队列最后一个，但不确认，留给下一次回滚用
            var v4 = queue.TakeOne();


            // 现在队列没有数据，再取一个
            var v5 = queue.TakeOne(1);

        }

        void Test55()
        {
            // 实例化Redis，默认端口6379可以省略，密码有两种写法
            var redids = new FullRedis("127.0.0.1:6379", "", 0);
            redids.Log = XTrace.Log;
            redids.ClientLog = XTrace.Log; // 调试日志。正式使用时注释

            var key = "Queue_block1";

            // 删除已有
            redids.Remove(key);


            var q = redids.GetQueue<string>(key);

            var list1 = redids.GetList<string>(key);

            // 取出个数
            var count = q.Count;


            // 添加
            var vs = new[] { "A,101", "A,102", "A,103", "B,201" };

            foreach (var item in vs)
            {
                q.Add(item);
            }


            var list2 = redids.GetList<string>(key);


            var abc = list2.LastOrDefault();

            var def = q.TakeOne();



            var list3 = redids.GetList<string>(key);


            XTrace.WriteLine($"TotalCount:{q.Count}");

            XTrace.WriteLine($"TakeOne1:{q.TakeOne()}");
            XTrace.WriteLine($"TakeOne1Count:{q.Count}");

            XTrace.WriteLine($"TakeOne2:{q.TakeOne()}");
            XTrace.WriteLine($"TakeOne2Count:{q.Count}");
        }

        void Test54()
        {
            var students = new List<Student>()
    {
        new Student() { Id = 1, Name = "A", Age = 31 },
        new Student() { Id = 2, Name = "B", Age = 32 },
        new Student() { Id = 3, Name = "C", Age = 33 }
    };

            var student = students.Where((A) => A.Id == 99).FirstOrDefault();

            XTrace.WriteLine(student.ToJson());

        }

        void Test53()
        {
            var input = "ABCDEFGH";

            StringBuilder sb = new StringBuilder(input.Length + (input.Length - 1) / 2);

            // 遍历字符串中的每个字符  
            for (int i = 0; i < input.Length; i++)
            {
                sb.Append(input[i]); // 添加当前字符  

                // 如果不是最后一个字符，并且索引是奇数（从0开始计数，所以实际上是每两个字符后添加'-'）  
                if (i < input.Length - 1 && (i + 1) % 2 == 0)
                {
                    sb.Append('-');
                }
            }

            XTrace.WriteLine(sb.ToString());
        }


        void Test52()
        {
            var str1 = "0".ToString();

            XTrace.WriteLine($"{ushort.Parse(str1)}");
        }
        void Test51()
        {
            var str1 = "A";
            string str2 = null;
            var str3 = "C";

            XTrace.WriteLine($"{str1}{str2}{str3}");
        }
    }
}
